package service

import (
	"errors"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	jwt "github.com/golang-jwt/jwt"
	"quabg/app/model"
	"strings"
	"time"
)

// https://blog.csdn.net/shachao888/article/details/111072282
// type StandardClaims struct {
// 	Audience  string `json:"aud,omitempty"` //该JWT所面向的用户
// 	ExpiresAt int64  `json:"exp,omitempty"` //token什么时候过期
// 	Id        string `json:"jti,omitempty"` //ID为web token提供唯一标识
// 	IssuedAt  int64  `json:"iat,omitempty"` //在什么时候签发的token
// 	Issuer    string `json:"iss,omitempty"` //该JWT的签发者
// 	NotBefore int64  `json:"nbf,omitempty"` //token在此时间之前不能被接收处理
// 	Subject   string `json:"sub,omitempty"` //
// }

var (
	_jwtSecret []byte
)

func init() {
	_jwtSecret = g.Cfg().GetBytes("jwtKey")
}

type Claims struct {
	model.ContextUserReq
	jwt.StandardClaims
}

// AuthHandler 接收http请求，解析token相关内容，然后给出token body
func AuthHandler(r *ghttp.Request) (*Claims, error) {
	// token from header Authorization or query parameter token
	token := r.Request.Header.Get("Authorization")
	if len(token) < 8 {
		token = r.GetQueryString("token")
		if len(token) < 8 {
			return nil, errors.New("缺少token相关参数")
		}
	} else {
		// split header token  => Bearer/Basic TEphZXI6MTIzNDU2
		token = strings.TrimSpace(token)
		tks := strings.Split(token, " ")
		if len(tks) != 2 {
			return nil, errors.New("token格式错误")
		}
		token = tks[1]
	}
	// parse
	cla, err := ParseToken(token)
	if err == nil {
		// check time
		if cla.ExpiresAt < time.Now().Unix() {
			return nil, errors.New("token已过期")
		}
	}
	// update content
	Context.SetUser(r.Context(), &cla.ContextUserReq)
	return cla, err
}

// GenerateToken 产生token的函数
func GenerateToken(id, role, group int, salt string) (string, error) {
	nowTime := time.Now()
	expireTime := nowTime.Add(24 * time.Hour)

	claims := Claims{
		model.ContextUserReq{
			Id:    id,
			Salt:  salt,
			Role:  role,
			Group: group,
		},
		jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    "gf-server",
		},
	}
	// make
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString(_jwtSecret)
	return token, err
}

// ParseToken 验证token的函数
func ParseToken(token string) (*Claims, error) {
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return _jwtSecret, nil
	})

	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}
	// error
	return nil, err
}
